﻿using System;
using System.Collections.Generic;
using System.Text;

namespace TestEffectiveCS
{
    class Test18
    {
        public class MyResourceHog : IDisposable
        {
            protected string name;

            protected bool suppressFinalize;

            private bool m_disposed;

            public MyResourceHog(string name)
                : this(name, true)
            {
            }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="name"></param>
            /// <param name="suppressFinalize">是否阻止调用析构函数</param>
            public MyResourceHog(string name, bool suppressFinalize)
            {
                this.name = name;

                this.suppressFinalize = suppressFinalize;
            }
            
            /// <summary>
            /// 释放资源，子类可继承
            /// </summary>
            /// <param name="disposing">
            /// 用于判断Dispose是由系统调用还是用户调用
            /// 如果为true表示用户调用，如果为false表示系统调用
            /// </param>
            protected virtual void Dispose(bool disposing)
            {
                if (!m_disposed)
                {//如果资源没有释放
                    if (disposing)
                    {//如果用户手动释放资源
                        // Release managed resources
                        Console.WriteLine(this.name + "用户Dispose()释放托管资源");
                    }
                    //释放非托管资源
                    ReleaseUnmanageResources();

                    m_disposed = true;//标记资源已释放
                }
                else
                {
                    Console.WriteLine(this.name + "资源已经释放");
                }
            }

            //将释放非托管资源设计成一个虚函数
            //提供在继承类中释放基类的资源的能力
            /* 这里列举几种常见的非托管资源：
             * ApplicationContext,Brush,Component,ComponentDesigner,
             * Container,Context,Cursor,FileStream,Font,Icon,Image,
             * Matrix,Object,OdbcDataReader,OleDBDataReader,Pen,Regex,
             * Socket,StreamWriter,Timer,Tooltip
             */
            protected virtual void ReleaseUnmanageResources()
            {
                // Release unmanaged resources
                Console.WriteLine(this.name + "系统或用户释放非托管资源");
            }
            
            //收系统垃圾回收器来调用，调用时间不确定
            //或者用户在调用GC.Collect()时执行此方法
            //析构函数，编译后变成 protected void Finalize()
            //GC会在回收对象前会调用调用该方法
            ~MyResourceHog()
            {
                //系统调用终结器
                Dispose(false);
                Console.WriteLine(this.name + "系统Finalize()释放资源");
            }

            #region IDisposable 成员
            /// <summary>
            /// 1，释放所有的非托管资源
            /// 2，释放所有的托管资源
            /// 3，设置状态标记，表示对象是否已经执行过Dispose方法
            /// 4，取消对象的终结操作。通过调用GC.SuppressFinalize(this)
            /// 实现在Dispose方法里面没有调用GC.SuppressFinalize(this)方
            /// 法会导致垃圾回收器不能对这个类型的对象及时回收. 当GC开
            /// 始工作的时候，它首先将没有终结器的垃圾对象从内存中移除，
            /// 有终结器的所有对象则添加到一个垃圾队列当中。GC会调用一
            /// 个新线程来执行这些对象的终结器。当终结器执行完毕后，这
            /// 个对象会从队列中被移除。这个对象在队列中移除之后,当GC再
            /// 次开始工作的时候,这个对象才能够被回收,所以有终结器的对
            /// 象会比没有的在内存中保留更长的时间。在Dispose方法中调用
            /// GC.SuppressFinalize(this)方法.这样的话,就不会把有终结器的
            /// 对象则添加到垃圾队列当中.
            /// </summary>
            public void Dispose()
            {
                Dispose(true);
                
                if (suppressFinalize) GC.SuppressFinalize(this);
            }

            #endregion
        }

        class DerivedResourceHog : MyResourceHog
        {
            private bool m_disposed;

            private string subname;

            public DerivedResourceHog(string name)
                : this(name, true)
            {
            }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="name"></param>
            /// <param name="suppressFinalize">是否阻止调用析构函数</param>
            public DerivedResourceHog(string name, bool suppressFinalize)
                : base(name, suppressFinalize)
            {
                subname = name + "子类 ";
            }

            protected override void ReleaseUnmanageResources()
            {
                Console.WriteLine(this.subname + "系统或用户释放非托管资源");

                base.ReleaseUnmanageResources();
            }

            protected override void Dispose(bool disposing)
            {
                if (!m_disposed)
                {
                    if (disposing)
                    {
                        Console.WriteLine(this.subname + "用户Dispose()释放托管资源");
                    }
                    //释放非托管资源
                    //此处不需要添加该函数
                    //该方法会在父类的Dispose(bool disposing)方法中被调用
                    //ReleaseUnmanageResources();

                    m_disposed = true;//标记资源已释放
                }
                else
                {
                    Console.WriteLine(this.subname + "资源已经释放");
                }

                base.Dispose(disposing);
            }
        }

        public Test18()
        {
            //当using作用完成时调用Dispose()方法
            //using中的对象必需支持IDisposable接口
            MyResourceHog mrh1 = new MyResourceHog("1",false);
            using (mrh1)
            {
                Console.WriteLine("使用using释放资源");
            }
            mrh1.Dispose();
            mrh1 = null;

            //如果对象可能支持也可能不支持IDisposable接口
            //则在using中使用as语句安全释放
            MyResourceHog mrh2 = new MyResourceHog("2", false);
            using (mrh2 as IDisposable)
            {
                Console.WriteLine("\n使用as安全释放未知资源");
            }
            mrh2.Dispose();
            mrh2 = null;

            GC.Collect();
            System.Threading.Thread.Sleep(3000);
            //注意：当使用using时，系统并未调用析构函数

            //直接调用Dispose()方法
            MyResourceHog mrh3 = new MyResourceHog("3", false);
            Console.WriteLine("\n直接手动释放资源");
            mrh3.Dispose();
            mrh3.Dispose();
            mrh3 = null;

            //利用try/finally释放资源
            MyResourceHog mrh4 = null;
            try
            {
                mrh4 = new MyResourceHog("4", false);
                Console.WriteLine("\n利用try/finally释放资源");
            }
            finally
            {
                if (mrh4 != null) mrh4.Dispose();
            }
            if (mrh4 != null) mrh4.Dispose();
            mrh4 = null;

            //强制系统回收
            MyResourceHog mrh5 = new MyResourceHog("5");
            mrh5 = null;
            Console.WriteLine("\n强制系统回收资源");
            GC.Collect();

            System.Threading.Thread.Sleep(3000);

            //子类释放资源
            MyResourceHog mrh6 = new DerivedResourceHog("6");
            Console.WriteLine("\n释放子类资源");
            mrh6.Dispose();
            mrh6 = null;
            GC.Collect();
        }
    }
}
